/*
 * CFile1.c
 *
 * Created: 2012-07-06 13:27:46
 *  Author: Antrykot
 */ 


#include "main.h"
#include "sc-k.h"
#include "utils.h"
#include "trans-k.h"
#include "digital.h"
#include "analog.h"


u8 crc_data[16];
u8 crc_data_len;

u8 rs_addr;
u16 rs_data;
u16 rs_pom;
u8 rs_crc;

u16 rs_pr = 0;
u16 rs_tm = 0;
u16 rs_rh = 0;

u8 ts_addr;
u8 ts_crc;
u16 ts_data;

u8 loop_cnt = 0;


u16 time_cnt_h = 0;
u16 time_cnt = 0;


u8 ts_repeat = 0;			// repeat current data K-->S x times;


void TS(u8 addr, u16 data, u8 repeat)
{
	ts_addr = addr;
	ts_data = data;
	ts_repeat = repeat;
}

#define CLKUS	30

void clk_s()
{
	KCLK_LOW;
	WAITUS(CLKUS);
	KCLK_HIGH;
	WAITUS(CLKUS);
}

u8 get_8b_s()
{
	static u8 byte = 0;
	static u8 val  = 0;
	static i8 c = 0;
	
	byte = 0;
	c = 7;
	
	for (; c >= 0; c--)
	{
		clk_s();	// wait for falling edge
		KTX_HIG;
		
		val = ( PIND & (1 << PIND4 )) >> PIND4;		 // read bit
		byte |= ( val << c );
		KTX_LOW;
		
	}
	WAITUS(CLKUS);
	return byte;
}

void set_8b_s(u8 data)
{
	static i8 c;
	c = 7;
	for (; c >= 0; c--)
	{
		if (data & (1 << c) )
		KTX_HIG;
		else
		KTX_LOW;			// setup data
		clk_s();		// wait for clk to became high again
	}
	//w_p_clk_l();
	WAITUS(CLKUS);
}




extern u16 xxx;
extern u16 yyy;

u8 repeated_trans = 0;

u8 trans_s()
{
	INT0_DISABLE;
	
	u16 old_pom = rs_pom;		// backup old meas
	
	crc_data_len = 0;
	add_crc8(ts_addr);
	add_crc16(ts_data);
	ts_crc = crc8(crc_data,crc_data_len);
	
	KCLK_LOW;			// get S to go into interrupt
	
	u8 c = 0;
	while (1)
	{
		if (!KRX)
		{
			WAITUS(CLKUS);
			break;
		}
		c++;
		if (c > 250)
		{
			KCLK_HIGH;
			INT0_ENABLE;
			return 0;		/// NO RESONSE FROM P - escape // 5ms (20us * 250)
		}			
		WAITUS(20);
	}

	KCLK_HIGH;
	
	
	set_8b_s(ts_addr);
	set_8b_s((ts_data & 0xFF00) >> 8);
	set_8b_s((ts_data & 0x00FF));
	set_8b_s(ts_crc);
	


	rs_addr = get_8b_s();

	rs_data = (get_8b_s() << 8);
	rs_data |= get_8b_s();
	rs_pom = (get_8b_s() << 8);
	rs_pom |= get_8b_s();
	rs_crc = get_8b_s();
	
	
	crc_data_len = 0;
	add_crc8(rs_addr);
	add_crc16(rs_data);
	add_crc16(rs_pom);
	
	u8 crc_r = crc8(crc_data,crc_data_len);
	if (crc_r == rs_crc)
		trs_ok = 1;
	else
		trs_ok = 0;
		
	clk_s();
	
	u8 was_not_ok = KRX;
	if (was_not_ok)		// if S didn't respond ok, transmision failed.	// high - failed to responde
		trs_ok = 0;

	
	KTX_HIG;
	KCLK_HIGH;
	
	if (ts_addr == K_ADDR_SYNC)
	{
		ts_addr = 0;
	}
	
	if(trs_ok)
	{
		if (ts_repeat)
		{
			ts_repeat--;
			
		}
		else
		{
			ts_addr = 0;
			ts_data = 0;
		}
		
		retrive_trans();
	}
	else
	{
		rs_pom = old_pom;		
		if (!repeated_trans)
		{
			repeated_trans = 1;
			trs_ok = trans_s();
		}
	}

	time_cnt++;
	
	if (!repeated_trans)		// If this is not a recurent fucntion.
		INT0_ENABLE;
	return trs_ok;
}

void retrive_trans()
{

	u16 m_type = (rs_pom & 0xC000);
	m_type = m_type >> 14;
	switch(m_type)
	{
		case 1:
			rs_pr = rs_pom & 0x3FFF;
			break;
		case 2:
			rs_rh = rs_pom & 0x3FFF;
			break;
		case 3:
			rs_tm = rs_pom & 0x3FFF;
			break;

	}
	
	
	//rs_pr = 10045;
	//rs_rh = 387;
	//rs_tm = 292 + 200;
	
	
	switch (rs_addr)
	{
		
		case K_ADDR_HRANGE:
		{
			h_range = rs_data;
			write_word(EEP_HRANGE,h_range);
			break;
		}
		
		case K_ADDR_LRANGE:
		{
			l_range = rs_data;
			write_word(EEP_LRANGE,l_range);
			break;
		}
		
		case  K_ADDR_RS_ASKNUM:
		{
			asknum = 0;
			break;
		}
		
		case K_ADDR_NR:
		{
			nr = rs_data;
			write_word(EEP_NR,nr);
			calc_num();
			break;
		}
		
		case K_ADDR_KSP:
		{
			modeftk = rs_data;
			_write(EEP_KSP,modeftk);
			
			// force reset after changing mode
			WDTCSR = (1 << WDE) | (1 << WDCE);
			WDTCSR = (1 << WDE) | (1 << WDCE);
			WAITMS(100);
			
			break;
		}
		
		case K_ADDR_CALFP:
		{
			fkal = _read(EEP_FKAL);
			fkal ++;
			if (fkal > 254)
				fkal = 254;
			cli();
			OSCCAL = fkal;
			sei();
			_write(EEP_FKAL,fkal);
			TS(K_ADDR_CALFP,fkal,1);

			break;
		}
		case K_ADDR_CALFM:
		{
			fkal = _read(EEP_FKAL);
			fkal --;
			if (fkal < 1)
			fkal = 1;
			cli();
			OSCCAL = fkal;
			sei();
			_write(EEP_FKAL,fkal);
			TS(K_ADDR_CALFP,fkal,1);


			break;
		}
		
		case K_ADDR_CAL_STOP:		// emergency stop ??
		{
			in_kalib = 0;
			wait_spec = 0;
			akal_ask = 0;
			kal_ask = KAL_IDLE;
			calc_freq();
			break;
		}
		
		case K_ADDR_CAL_START:
		{
			in_kalib = 0;
			akal_ask = KAL_ASK;
			kal_ask = KAL_ASK;
			break;
		}		
		
		case K_ADDR_CAL_FINISH:
		{
			if (rs_data)
			{
				akal_ask = KAL_FINISHERR;
				kal_ask = KAL_FINISHERR;
				freq = 4000;
			}
			else
			{
				akal_ask = KAL_FINISHOK;
				kal_ask = KAL_FINISHOK;
				freq = 3500;
			}
			in_kalib = 0;
			break;
		}
		
		case K_ADDR_HZ:
		{
			freq = 10500;
			wait_spec = 1;
			kal_ask = KAL_ZERO_H;
			kal_meas = rs_data;
			break;
		}
		
		case K_ADDR_HS:
		{
			freq = 10500 + (rs_data * 1.5);
			wait_spec = 1;
			kal_ask = KAL_SENS_H;
			kal_meas = rs_data;
			break;
		}
		
		case K_ADDR_LZ:
		{
			freq = 10000;
			wait_spec = 1;
			kal_ask = KAL_ZERO_L;
			kal_meas = rs_data;
			break;
		}
		case K_ADDR_LS:
		{
			kal_ask = KAL_SENS_L;
			
#if defined(MEDIA_CH4) ||  defined(MEDIA_CH4IR)		
			freq = 10000 - (rs_data * 10);		// 5%CH4
		
#elif MEDIA_CON
			freq = 10000 - (rs_data * 25);		// 200ppm
#elif MEDIA_COS
	freq = 10000 - (rs_data * 5);		// 1000ppm
#elif MEDIA_CO2
	freq = 10000 - (rs_data * 10);		// 5%CH4
#else
			freq = 4500;		// NOT DEFINED
#endif
			wait_spec = 1;
			kal_meas = rs_data;
			break;
		}

		case K_ADDR_SERWIS:
		{
			kal_ask = KAL_SERWIS;
			kal_meas = rs_data;
		}

		case K_ADDR_DEBUG_AL:
		{
			//ts_data = debug_alarms;
			//ts_addr = K_ADDR_DEBUG;
			TS(K_ADDR_DEBUG,debug_alarms,1);
			break;
		}
		
		case K_ADDR_DATE:
		{
			leg_date = rs_data;
			write_word(EEP_DATE,leg_date);
			break;
		}
		
		case K_ADDR_BATT_VOLT:
		{
			v_aku = rs_data;
			break;
		}
		case K_ADDR_LINE_VOLT:
		{
			v_pow = rs_data;
			break;
		}
		case K_ADDR_LINE_LOAD:
		{
			v_cur = rs_data; 
			break;
		}
		case K_ADDR_PELI_VOLT:
		{
			v_dc = rs_data;
			break;
		}
		case K_ADDR_INPUT:
		{
			ds_alstate = rs_data;
		}
		
	}


}




u8 crc()
{
	u8 crc8 = 0;
	for (u8 c = 0; c < crc_data_len; c++)
	{
		crc8 ^= crc_data[c];
		for(u8 i = 0; i < 8; i++)
		{
			if(crc8 & 0x80)
			crc8 = (crc8 << 1) ^ 0xE5;
			else
			//crc <<= 1;
			crc8 = (crc8 <<  1);
		}
		
	}
	return crc8;
}


void add_crc8(u8 byte)
{
	crc_data[crc_data_len] = byte;
	crc_data_len++;
}

void add_crc16(u16 word)
{
	crc_data[crc_data_len] = (word & 0xFF00) >> 8;
	crc_data_len ++;
	crc_data[crc_data_len] = (word & 0xFF) ;
	crc_data_len ++;
}

u8 trs_ok = 0;